#ifndef __LIOMUSIC_H
#define __LIOMUSIC_H

#include "liobase.h"

#define MCI_ERROR_STR 128 

namespace Lio {

BOOL playSound(CSTR filename,BOOL repeat);
void stopSound();

typedef struct MidiCommand
{
	WORD id;
	String str;
	DWORD val;
} MidiCommand;

class MidiPlayer: public Runnable
{
protected:
	UINT wDeviceID;
	HWND h;
	WORD state;
	DWORD error,div,tempo;
	DWORD_PTR wndNotify;
	MCI_OPEN_PARMS mciOpenParms;
	MCI_PLAY_PARMS mciPlayParms;
	MCI_GENERIC_PARMS mciGenParms;
	MCI_SEQ_SET_PARMS mciSetParms;
	MCI_STATUS_PARMS mciStatParms;
	List<MidiCommand> commands;
	_TCHAR errorStr[MCI_ERROR_STR];
	CriticalSection cs;
	HANDLE running_thread;
	Event command_available;
	ThreadInfo ti;
	DWORD run(const ThreadInfo *ti);
public:
	enum CommID{
		MIDI_COMM_OPEN,
		MIDI_COMM_CLOSE,
		MIDI_COMM_PLAY,
		MIDI_COMM_PAUSE,
		MIDI_COMM_SET_TEMPO,
		MIDI_COMM_GET_TEMPO,
		MIDI_COMM_GET_DIV,
		MIDI_COMM_COUNT
	};
	WORD status,msg;
	enum States{
		MIDI_STATE_CLOSED,
		MIDI_STATE_CLOSE,
		MIDI_STATE_OPENED,
		MIDI_STATE_OPEN,
		MIDI_STATE_PLAYED,
		MIDI_STATE_PLAY,
		MIDI_STATE_PAUSED,
		MIDI_STATE_PAUSE,
		MIDI_STATE_COUNT
	};
	MidiPlayer(HWND window = NULL):
		error(0),status(0),state(MIDI_STATE_CLOSED),tempo(0),div(MCI_SEQ_DIV_PPQN),
		wDeviceID(MIDI_MAPPER),msg(0),running_thread(NULL)
	{
		ClearStruct(mciOpenParms);
		ClearStruct(mciPlayParms);
		ClearStruct(mciGenParms);
		ClearStruct(mciSetParms);
		ClearStruct(mciStatParms);
		ClearMemory(errorStr,sizeof(errorStr));

		mciOpenParms.lpstrDeviceType = _T("sequencer");
		setWindow(window);

		ti.caller = this;
		ti.name = _T("MidiPlayer");
	}
	~MidiPlayer()
	{
		close();
	}
	
	void start()
	{
		Runnable::start(&ti);
	}

	void open(CSTR midiName)
	{
		send(MIDI_COMM_CLOSE);
		send(MIDI_COMM_OPEN,midiName);
		send(MIDI_COMM_GET_TEMPO);
		send(MIDI_COMM_GET_DIV);
	}
	void pause()
	{
		send(MIDI_COMM_PAUSE,NULL);
	}
	void close()
	{
		send(MIDI_COMM_CLOSE,NULL);
	}
	void setTempo(DWORD tempo)
	{
		send(MIDI_COMM_SET_TEMPO,NULL,tempo);
	}
	void play(CSTR midiName = NULL, DWORD tempo = 0)
	{
		if(midiName)
		{
			send(MIDI_COMM_CLOSE);
			send(MIDI_COMM_OPEN,midiName);
		}
		send(MIDI_COMM_PLAY);
		if(tempo)
			send(MIDI_COMM_SET_TEMPO,NULL,tempo);
	}
	void reset();
	void setWindow(HWND hWnd);
	BOOL send(WORD id, CSTR str = NULL, DWORD val = 0);
	BOOL notify(LPARAM lParam, WPARAM wParam);
	UINT getDeviceID() const {return wDeviceID;}
	DWORD getError()const{return error;}
	CSTR getErrorStr();
	DWORD getState()const{return state;}
	DWORD getTempo()const{return tempo;}
	DWORD getDiv()const{return div;}
};

}; //namespace Lio

#endif // __LIOMUSIC_H